//run omp & sequential solver
//$Id: run_omp.h 395 2010-03-26 14:01:03Z Oleg.Bulychov $
#pragma once

#include "src/heo/include/lf_endl.h"
#include "src/heo/include/fast_stream.h"
#include "src/heo/include/stream_visitor.h"
#include "src/heo/include/run_environment.h"


template<class TSolver>
struct Run_OMP
{
    typedef typename TSolver::TEnvironment   TEnvironment;
    typedef typename TEnvironment::TProblem  TProblem;
    typedef typename TEnvironment::TSolution TSolution;
    typedef typename TEnvironment::TConfig   TConfig;

    int retval_;
    operator int() const { return retval_; }

    int run(int argc, char* argv[])
    {
        using namespace std;

        setlocale(LC_ALL, "C");//:decimal point must be '.'

        if (argc != 3)
        {
            cout << "usage: " << argv[0] << " randseed file.xml" << endl;
            return -1;
        }
        for (int i = 0; i < argc; ++i)
        {
            cout << "argv[" << i << "]='" << argv[i] << "'" << endl;
        }

#if defined(_OPENMP)
        cout << "omp processors available: " << omp_get_num_procs() << lf;
#pragma omp parallel
        {
#pragma omp critical
            cout << "thread: " << omp_get_thread_num() << " from " << omp_get_num_threads() << lf;
        }
#else
        cout << "sequential version" << lf;
#endif


        TEnvironment env;
        TSolver solver;

        env.rand_seed_ = ::strtol(argv[1], NULL, 0);
        bool load_ok = env.property_tree_.load(argv[2]);
        env.property_tree_.parse();
        xml::in in(env.property_tree_);
        in >> env;
        in >> solver;

        meta::ostream_visitor kcout(cout);
        kcout(env, "");//:hide ugly name
        cout << endl;
        kcout << solver;
        cout << endl;

        if (!load_ok)
        {
            xml::out out(env.property_tree_);
            out << env;
            out << solver;
            env.property_tree_.save(argv[2]);
            cout << "new file '" << argv[2] << "' created" << endl;
            return -1;
        }

        uniform_random::randomize(omp_get_max_threads(), env.rand_seed_, 0);

        if (env.input_file_.length() > 0)
        {
            fast_istream2 ifs;
            if (!ifs.open(env.input_file_.c_str()))
            {
                cout << "ERROR: can not open '" << env.input_file_ << "'" << endl;
                return -1;
            }
            uniform_random rnd(0);
            if (!env.problem_.read(ifs, &env, rnd))
            {
                cout << "ERROR: '" << env.input_file_ << "' corrupted" << endl;
                return -1;
            }
        }
        else
        {
            if (env.problem_.get_Default_File_Name() && *env.problem_.get_Default_File_Name())
            {
                cout << "ERROR: input file missing" << endl;
                return -1;
            }
        }

        double start_time = omp_get_wtime();
        solver.init(&env, 0, 0);
        Solution_Pool<TSolution> pool;
        if (!pool.init(solver))
            return -1;
        for (int n = 1; n <= env.run_count_; ++n)
        {
            solver.solve(pool);
        }
        double end_time = omp_get_wtime();

        cout << "time = " << end_time - start_time << " s" << lf;
            //<< "solution:" << lf;
        pool.output(&env);
        //sol.print(cout, &env);
        return 0;
    }

    Run_OMP(int argc, char* argv[])
    {
        retval_ = run(argc, argv);
#if defined(_MSC_VER)
        extern void If_Debug_Press_Enter();
        If_Debug_Press_Enter();
#endif
    }
};

//EOF!
